﻿using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace DotNetStar.TheKing.Web
{
    using Microsoft.AspNetCore.Html;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc.Rendering;
    using Microsoft.AspNetCore.Mvc.ViewFeatures;
    using Services;
    using System.Text.RegularExpressions;

    public static class WebExtension
    {
        /// <summary>
        /// 返回一个页面响应的结果。成功返回 OK:200；有错误将返回 BadRequest :400 以“;”分割。
        /// </summary>
        /// <param name="result">The result.</param>
        /// <returns></returns>
        public static IActionResult ReturnActionResult(this ExecutedResult result)
        {
            if (result.IsSucceed)
            {
                return new OkResult();
            }
            return new BadRequestObjectResult(result.Errors.Join(";"));
        }

        /// <summary>
        /// 返回一个页面响应的结果。成功返回 OK:200，并返回定义的数据；有错误将返回 BadRequest :400 以“;”分割。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="result">The result.</param>
        /// <returns></returns>
        public static IActionResult ReturnActionResult<T>(this ExecutedResult<T> result)
        {
            if (result.IsSucceed)
            {
                return new JsonResult(result.Data);
            }
            return new BadRequestObjectResult(result.Errors.Join(";"));
        }

        /// <summary>
        /// 以异步方式返回一个页面响应的结果。成功返回 OK:200；有错误将返回 BadRequest :400 以“;”分割。
        /// </summary>
        /// <param name="result">The result.</param>
        /// <returns></returns>
        public static async Task<IActionResult> ReturnActionResultAsync(this Task<ExecutedResult> result)
                    => (await result).ReturnActionResult();

        /// <summary>
        /// 以异步方式返回一个页面响应的结果。成功返回 OK:200，并返回定义的数据；有错误将返回 BadRequest :400 以“;”分割。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="result">The result.</param>
        /// <returns></returns>
        public static async Task<IActionResult> ReturnActionResultAsync<T>(this Task<ExecutedResult<T>> result)
                    => (await result).ReturnActionResult<T>();
        
            public static IHtmlContent Pagination<T>(this IHtmlHelper htmlHelper, PagedCollection<T> collection, PageButtonOptions options = default(PageButtonOptions))
            {

                if (options == null)
                {
                    options = new PageButtonOptions();
                }

                if (collection.Count == 0 || collection.ItemsPerPage == 0)
                {
                    return HtmlString.Empty;
                }
                var totalPages = collection.TotalPages;
                //未超过一页时不显示分页按钮
                if (!options.AlwaysShow && totalPages <= 1)
                {
                    return HtmlString.Empty;
                }

                var pageIndex = collection.CurrentPage;

                bool showNumberic = false;
                bool showFirst = false;
                bool showLast = false;
                bool showPrevious = false;
                bool showNext = false;
                var mode = options.ButtonMode;
                if (mode == PageButtonMode.FirstLastNumberic || mode == PageButtonMode.PreviousNextFirstLastNumberic || mode == PageButtonMode.PreviousNextNumberic || mode == PageButtonMode.OnlyNumberic)
                {
                    showNumberic = true;
                }

                if (mode == PageButtonMode.FirstLastNumberic || mode == PageButtonMode.PreviousNextFirstLast || mode == PageButtonMode.PreviousNextFirstLastNumberic)
                {
                    showFirst = true;
                    showLast = true;
                }

                if (mode == PageButtonMode.PreviousNext || mode == PageButtonMode.PreviousNextFirstLast || mode == PageButtonMode.PreviousNextFirstLastNumberic || mode == PageButtonMode.PreviousNextNumberic)
                {
                    showPrevious = true;
                    showNext = true;
                }

                string firstText = options.TextOfFirst;
                string previouseText = options.TextOfPrevious;
                string nextText = options.TextOfNext;
                string lastText = options.TextOfLast;

                //分页字符串
                TagBuilder pageBuilder = new TagBuilder("ul");

                pageBuilder.AddCssClass("pagination");

                pageBuilder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(options.HtmlAttributes));

                if (showFirst)
                {
                    htmlHelper.GeneratePageButton(pageBuilder, pageIndex <= 1, 1, firstText, options);
                }

                if (showPrevious)
                {
                    htmlHelper.GeneratePageButton(pageBuilder, pageIndex - 1 < 1, pageIndex - 1, previouseText, options);
                }

                #region 计算页数

                if (showNumberic)
                {
                    long startPage = 1;
                    long endPage = 1;
                    int numbericCount = options.NumbericCount;
                    if (totalPages > numbericCount)
                    {
                        if (pageIndex - (numbericCount / 2) > 0)
                        {
                            if (pageIndex + (numbericCount / 2) < totalPages)
                            {
                                startPage = pageIndex - (numbericCount / 2);
                                endPage = startPage + numbericCount - 1;
                            }
                            else
                            {
                                endPage = totalPages;
                                startPage = endPage - numbericCount + 1;
                            }
                        }
                        else
                        {
                            endPage = numbericCount;
                        }
                    }
                    else
                    {
                        startPage = 1;
                        endPage = totalPages;
                    }

                    for (var i = startPage; i <= endPage; i++)
                    {
                        htmlHelper.GeneratePageButton(pageBuilder, i == collection.CurrentPage, i, i.ToString(), options, i == collection.CurrentPage);
                    }
                }
                #endregion

                if (showNext)
                {
                    htmlHelper.GeneratePageButton(pageBuilder, pageIndex + 1 > totalPages, pageIndex + 1, nextText, options);
                }

                if (showLast)
                {
                    htmlHelper.GeneratePageButton(pageBuilder, pageIndex >= totalPages, totalPages, lastText, options);
                }
                return pageBuilder;
            }

            /// <summary>
            /// 生成分页链接Url
            /// </summary>
            /// <param name="htmlHelper">HtmlHelper</param>
            /// <param name="page">页码</param>
            /// <param name="options">配置</param>
            /// <returns></returns>
            static string GeneratePaginationUrl(this IHtmlHelper htmlHelper, long page, PageButtonOptions options)
            {

                var currentUrl = htmlHelper.ViewContext.HttpContext.Request.QueryString.ToUriComponent();

            if (currentUrl.IndexOf("?") == -1)
                {
                    return string.Format("{0}?page={1}", currentUrl, page);
                }

                if (currentUrl.IndexOf("page=", StringComparison.InvariantCultureIgnoreCase) == -1)
                {
                    return string.Format("{0}&page={1}", currentUrl, page);
                }
                return Regex.Replace(currentUrl, @"page=(\d+\.?\d*|\.\d+)", $"page={page}", RegexOptions.IgnoreCase | RegexOptions.Compiled);
            }

        static void GeneratePageButton(this IHtmlHelper htmlHelper,
   TagBuilder pageBuilder,
   bool canClick, long page, string text, PageButtonOptions options, bool current = false)
        {
            TagBuilder liTag = new TagBuilder("li");
            liTag.AddCssClass("page-item");
            if (canClick)
            {
                if (current)
                {
                    liTag.AddCssClass("active");
                }
                else
                {
                    liTag.AddCssClass("disabled");
                }
                liTag.InnerHtml.AppendHtml($"<span class='page-link'>{text}</span>");
            }
            else
            {
                liTag.InnerHtml.AppendHtml(string.Format("<a  class='page-link' href='{0}'>{1}</a>", htmlHelper.GeneratePaginationUrl(page, options), text));
            }

            pageBuilder.InnerHtml.AppendHtml(liTag);
        }


        /// <summary>
        /// 分页按钮控件配置。
        /// </summary>
        public class PageButtonOptions
        {
            /// <summary>
            /// 初始化 <see cref="PageButtonOptions"/> 类的新实例。
            /// </summary>
            public PageButtonOptions()
            {
                //this.NumbericCount = 10;
                // this.AlwaysShow = true;
                //this.ButtonMode = PageButtonMode.PreviousNextFirstLastNumberic;
                ////this.ContainerTag = "ul";
            }
            /// <summary>
            /// 获取或设置分页显示的数字的数目。若设置为3，表示在中间的数字数目只显示近3页的数字；例如这样的形式：首页 上一页 2 3 4 下一页 末页。
            /// </summary>
            public int NumbericCount { get; set; } = 10;
            /// <summary>
            /// 获取或设置分页按钮是否一直显示。若为 true，当第一页的数据没有达到所需要分页的数据量时，分页组件将一直显示。否则，直到数据可以分页时才显示。
            /// </summary>
            public bool AlwaysShow { get; set; } = true;
            /// <summary>
            /// 获取或设置分页按钮显示的模式。
            /// </summary>
            public PageButtonMode ButtonMode { get; set; } = PageButtonMode.PreviousNextNumberic;

            /// <summary>
            /// 获取或设置“首页”的文本，支持 HTML 文本。
            /// </summary>
            public string TextOfFirst { get; set; } = "首页";

            /// <summary>
            /// 获取或设置“上一页”的文本，支持 HTML 文本。
            /// </summary>
            public string TextOfPrevious { get; set; } = "上一页";

            /// <summary>
            /// 获取或设置“下一页”的文本，支持 HTML 文本。
            /// </summary>
            public string TextOfNext { get; set; } = "下一页";

            /// <summary>
            /// 获取或设置“末页”的文本，支持 HTML 文本。
            /// </summary>
            public string TextOfLast { get; set; } = "末页";

            /// <summary>
            /// 获取或设置一个对象，其中包含要为该元素设置的 HTML 特性。
            /// </summary>
            public object HtmlAttributes { get; set; }

            /// <summary>
            /// 获取或设置路由名称。
            /// </summary>
            public string RouteName { get; set; }
            /// <summary>
            /// 获取或设置控制器名称。
            /// </summary>
            public string ControllerName { get; set; }
            /// <summary>
            /// 获取或设置行为名称。
            /// </summary>
            public string ActionName { get; set; }
        }


        public static string ToRelativeUrl(this HttpRequest request)
            => $"{request.Path.ToUriComponent()}{request.QueryString.ToUriComponent()}";

        public static string ToAbsoluteUrl(this HttpRequest request)
            => $"{request.Scheme}://{request.Host.ToUriComponent()}{request.ToRelativeUrl()}";

        /// <summary>
        /// Api 状态
        /// </summary>
        /// <param name="controller"></param>
        /// <param name="statusCode">状态码</param>
        /// <param name="messages">自定义消息，可选</param>
        /// <returns></returns>
        public static ApiStatusResult ApiStatus(this ControllerBase controller, StatusCodeEnums statusCode, IEnumerable<string> messages = default(IEnumerable<string>))
            => new ApiStatusResult(statusCode,messages);

        public static ApiStatusResult ApiStatus(this ControllerBase controller, StatusCodeEnums statusCode, params string[] messages)
            => new ApiStatusResult(statusCode, messages);

        public static IHtmlContent RenderRankBadge(this IHtmlHelper helper,int index=1)
        {
            var tagBuilder = new TagBuilder("span");
            string color = "secondary";
            switch (index)
            {
                case 1:color = "danger";
                    break;
                case 2:color = "warning";
                    break;
                case 3:color = "primary";
                    break;
                default:
                    break;
            }

            tagBuilder.AddCssClass($"badge badge-{color}");
            tagBuilder.InnerHtml.SetContent(index.ToString());
            return tagBuilder;
        }

        public static IEnumerable<SelectListItem> GetEnumSelectItems<T>(this IHtmlHelper helper) where T: struct
        {
            var items = typeof(T).GetEnumItems();

            var itemList = new List<SelectListItem>(items.Count);

            foreach (var item in items)
            {
                itemList.Add(new SelectListItem { Text = item.Key, Value = item.Value.ToString() });
            }
            return itemList;
        }

        public static IEnumerable<SelectListItem> GenerateSelectItems<TKey,TValue>(this IEnumerable<KeyValuePair<TKey,TValue>> collections)
        {
            var itemList = new List<SelectListItem>(collections.Count());

            foreach (var item in collections)
            {
                itemList.Add(new SelectListItem { Text = item.Key.ToString(), Value = item.Value.ToString() });
            }
            return itemList;
        }
    }


    /// <summary>
    /// 分页按钮模式
    /// </summary>
    public enum PageButtonMode
    {
        /// <summary>
        /// 上一页，下一页
        /// </summary>
        PreviousNext,
        /// <summary>
        /// 上一页，下一页，分页数字
        /// </summary>
        PreviousNextNumberic,
        /// <summary>
        /// 上一页，下一页，首页，末页
        /// </summary>
        PreviousNextFirstLast,
        /// <summary>
        /// 首页，末页，分页数字
        /// </summary>
        FirstLastNumberic,
        /// <summary>
        /// 上一页，下一页，首页，末页，分页数字
        /// </summary>
        PreviousNextFirstLastNumberic,
        /// <summary>
        /// 只显示数字
        /// </summary>
        OnlyNumberic,
    }
}
